package com.serkol.annotation;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.serkol.ams.entity.LoginLog;
import com.serkol.constant.ResultCode;
import com.serkol.exception.AuthException;
import com.serkol.utils.TokenUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class RedisCacheAspect {
    private ThreadLocal<SimpleDateFormat> format = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    @Autowired
    private RedisTemplate stringRedisTemplate;

    //切点表达式，表示加了Auth注解的都是切点，路径是自定义注解的全路径
    @Pointcut("@annotation(RedisCache)")
    public void pointcut() {

    }

    @Around("@annotation(redis)")
    public Object operationLogRecord(ProceedingJoinPoint joinPoint, RedisCache redis) throws AuthException, ClassNotFoundException {


        // 定义Jackson2JsonRedisSerializer序列化对象
        Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class);

        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域，field,get和set,以及修饰符范围，ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型，类必须是非final修饰的，final修饰的类，比如String,Integer等会报异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);
        StringRedisSerializer stringSerial = new StringRedisSerializer();
        // redis key 序列化方式使用stringSerial
        stringRedisTemplate.setKeySerializer(stringSerial);
        // redis value 序列化方式使用jackson
        stringRedisTemplate.setValueSerializer(jacksonSeial);
        // redis hash key 序列化方式使用stringSerial
        stringRedisTemplate.setHashKeySerializer(stringSerial);
        // redis hash value 序列化方式使用jackson
        stringRedisTemplate.setHashValueSerializer(jacksonSeial);
        stringRedisTemplate.afterPropertiesSet();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        StringBuilder sb = new StringBuilder();
        System.out.println("------------------------REDIS--------------------------");
        System.out.println(joinPoint);
        Object target = joinPoint.getTarget();

        Class<?> aClass = target.getClass();
       // System.out.println(aClass.getSimpleName());
        String authorization = request.getHeader("Authorization");
        String lang = request.getHeader("language");
        if (redis.isLang()) {
            sb.append(lang);
            sb.append("::");
        }

        sb.append(redis.key());


        if (redis.isAuth()) {
            if (StringUtils.isNotEmpty(authorization)) {
                LoginLog auth = TokenUtils.getAuth(authorization);
                if (redis.isAgent()) {
                    sb.append("::agent");
                    sb.append(auth.getAgentId());
                }
              //  System.out.println(auth);
            }
        }
        if (redis.isParam()) {
            Object[] args = joinPoint.getArgs();
            if (args.length > 0) {
                for (int i = 0; i < args.length; i++) {
                    Object arg = args[i];
                    sb.append("::");
                    sb.append(String.valueOf(arg));
                }
            }
        }


      //  System.out.println(redis);
       // System.out.println(sb.toString());
        Object o = stringRedisTemplate.opsForValue().get(sb.toString());
        if (o != null) {
          //  System.out.println("-------------------------OK----------------------");
         //   System.out.println(o);

            return o;
        }
        //响应
        Object responseResult = null;
        try {

            Object proceed = joinPoint.proceed();

            String s =proceed!=null? proceed.toString():"";
            if(StringUtils.isNotEmpty(s)) {
                stringRedisTemplate.opsForValue().set(sb.toString(), proceed);
                 long time = redis.time();
                 if(time>0) {
                     stringRedisTemplate.expire(sb.toString(), time, TimeUnit.MINUTES);
                 }
            }
            //返回切点处继续执行原方法，并接收原方法的响应
            responseResult = proceed;

        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println("3原方法报错，不需要记录日志");
            throw new AuthException(ResultCode.REQUEST_ERROR_FORBIDDEN);
        }


        return responseResult;
    }

}